package com.myk.game.gobangchess;

import com.myk.game.gobangchess.constants.ChatLevel;
import com.myk.game.gobangchess.constants.Msger;
import com.myk.game.gobangchess.dates.*;
import com.myk.game.gobangchess.utils.DateTimeUtil;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 管理员类
 */
public class Manager implements Runnable {
    private Socket socket;
    private DataOutputStream dos;
    private DataInputStream dis;
    private volatile boolean keepFlag;
    private volatile long heartTime;

    public Manager(Socket socket, DataOutputStream dos, DataInputStream dis) {
        this.socket = socket;
        this.dos = dos;
        this.dis = dis;
    }

    @Override
    public void run() {
        while (keepFlag) {
            try {
                handlerMessage(dis.readUTF());
            }
            catch (Exception e) {
                e.printStackTrace();
                System.out.println("管理员异常断线");
                DataManager.managerLogout(this);
                recycle();
            }
        }
    }

    //接收到客户端发送的消息后如何处理
    private void handlerMessage(String msg) {
        heartTime = System.currentTimeMillis();
        String type = Msger.getMsgType(msg);
        switch (type) {
            //保持存活
            case Msger.keepLive: {
                sendMessage(Msger.keepLive, "Ok");
                break;
            }
            //管理员申请退出
            case Msger.requestManagerLogout: {
                DataManager.managerLogout(this);
                recycle();
                break;
            }
            //刷新所有账号列表信息
            case Msger.requestAccountList: {
                sendMessage(Msger.refreshAccountList, AccountData.getAccountListInfo(account -> true));
                break;
            }
            //刷新所有封禁账号列表信息
            case Msger.requestSearchBanAccountList: {
                sendMessage(Msger.refreshAccountList, AccountData.getAccountListInfo(AccountData::isAccountUnderBan));
                break;
            }
            //刷新所有审核账号列表信息
            case Msger.requestSearchCheckAccountList: {
                sendMessage(Msger.refreshAccountList, AccountData.getAccountListInfo(AccountData::isAccountUnderReview));
                break;
            }
            //刷新模糊搜索昵称后的账号列表信息
            case Msger.requestSearchLikeNameAccountList: {
                String likeName = Msger.getValueByType(msg, Msger.requestSearchLikeNameAccountList);
                if (likeName == null || likeName.equals("-1")) {
                    sendMessage(Msger.refreshAccountList, AccountData.getAccountListInfo(account -> true));
                }
                else {
                    sendMessage(Msger.refreshAccountList, AccountData.getAccountListInfo(account -> account.getNickName().contains(likeName)));
                }
                break;
            }
            //获取账号详情
            case Msger.requestAccountDetail: {
                String idCode = Msger.getValueByType(msg, Msger.requestAccountDetail);
                Account account = AccountData.getAccountByIdCode(idCode);
                if (account != null) {
                    String detail = AccountData.getAccountDetail(account);
                    sendMessage(Msger.refreshAccountDetail, detail);
                }
                else {
                    sendMessage(Msger.broadcast, "获取账号详情失败");
                }
                break;
            }
            //获取资产明细
            case Msger.requestAmountDetail: {
                String idCode = Msger.getValueByType(msg, Msger.requestAmountDetail);
                Account account = AccountData.getAccountByIdCode(idCode);
                if (account != null) {
                    String detail = AmountData.getAmountDetail(account);
                    sendMessage(Msger.refreshAmountDetail, detail);
                }
                else {
                    sendMessage(Msger.broadcast, "获取资产明细失败");
                }
                break;
            }
            //获取对弈记录
            case Msger.requestPlayingDetail: {
                String idCode = Msger.getValueByType(msg, Msger.requestPlayingDetail);
                Account account = AccountData.getAccountByIdCode(idCode);
                if (account != null) {
                    String detail = PlayingData.getPlayingDetail(account);
                    sendMessage(Msger.refreshPlayingDetail, detail);
                }
                else {
                    sendMessage(Msger.broadcast, "获取对弈记录失败");
                }
                break;
            }
            //获取聊天权限情况
            case Msger.requestChatAdjustDetail: {
                String idCode = Msger.getValueByType(msg, Msger.requestChatAdjustDetail);
                Account account = AccountData.getAccountByIdCode(idCode);
                if (account != null) {
                    String detail = ChatData.getChatAdjustDetail(account);
                    sendMessage(Msger.refreshChatAdjustDetail, detail);
                }
                else {
                    sendMessage(Msger.broadcast, "获取聊天权限失败");
                }
                break;
            }
            //请求审核通过账号
            case Msger.requestPassAccount: {
                String id = Msger.getValueByType(msg, Msger.requestPassAccount);
                Account account = AccountData.getAccountByIdCode(id);
                if (account != null) {
                    String tempNickname = AccountData.getNickNameOrTemp(account);
                    AccountData.setAccountPassCheck(account);
                    sendMessage(Msger.broadcast, "账号审核通过完成");
                    Player player = DataManager.getOnlinePlayerById(account.getIdCode()); //查询该账户角色是否在线
                    if (player != null) {
                        player.sendMessage(Msger.refreshPlayerInfo, player.getPlayerInfo()); //更新角色信息
                        if (player.getEnteringRoom() != null) { //用户如果在房间内
                            player.getEnteringRoom().noticeAllRefreshRoomInfo();
                            player.getEnteringRoom().noticeAllRefreshGameInfo();
                        }
                        DataManager.noticeAllBroadcast("恭喜" + tempNickname + "账号审核通过！\n昵称恢复为：" + account.getNickName());//发送全局消息给所有在线用户
                    }
                }
                else {
                    sendMessage(Msger.broadcast, "该账号已不存在");
                }
                sendMessage(Msger.refreshAccountList, AccountData.getAccountListInfo(accountItem -> true)); //更新账号列表信息
                break;
            }
            //请求审核拒绝账号
            case Msger.requestRejectAccount: {
                String id = Msger.getValueByType(msg, Msger.requestRejectAccount);
                Account account = AccountData.getAccountByIdCode(id);
                if (account != null) {
                    String tempNickname = AccountData.getNickNameOrTemp(account);
                    AccountData.setAccountRejectCheck(account); //拒绝账户通过审核（封禁该账号）
                    sendMessage(Msger.broadcast, "已封禁该账号");
                    Player player = DataManager.getOnlinePlayerById(account.getIdCode()); //查询该账户角色是否在线
                    if (player != null) {
                        Room room = player.getEnteringRoom();
                        if (room != null) {
                            room.removeAllPlayer();
                        }
                        DataManager.noticeAllBroadcast(tempNickname + "账号被管理员拒绝通过审核强制退出");//发送全局消息给所有在线用户
                        DataManager.playerLogout(player);
                        player.recycle();
                    }
                }
                else {
                    sendMessage(Msger.broadcast, "该账号不存在");
                }
                sendMessage(Msger.refreshAccountList, AccountData.getAccountListInfo(accountItem -> true)); //更新账号列表信息
                break;
            }
            //管理员增加或者减少逆界代币额度
            case Msger.requestChangeAmount: {
                String data = Msger.getValueByType(msg, Msger.requestChangeAmount);
                if (data != null) {
                    String[] strs = data.split("&");
                    String idCode = strs[0];
                    int amount = Integer.parseInt(strs[1]);
                    String reason = strs[2];
                    Account account = AccountData.getAccountByIdCode(idCode);
                    if (account != null) {
                        boolean changeSuccFlag = AmountData.changePlayerAmount(account, amount, reason);
                        if (changeSuccFlag) {
                            String detail = AmountData.getAmountDetail(account);
                            sendMessage(Msger.refreshAmountDetail, detail);
                            sendMessage(Msger.broadcast, "额度修改成功");
                            Player player = DataManager.getOnlinePlayerById(account.getIdCode()); //查询该账户角色是否在线
                            if (player != null) {
                                player.sendMessage(Msger.refreshPlayerInfo, player.getPlayerInfo()); //更新角色信息
                                player.sendMessage(Msger.broadcast, "您的代币余额" + (amount > 0 ? "增加" : "减少") + Math.abs(amount) + "元" + "\n(" + reason + ")");
                            }
                        }
                        else {
                            sendMessage(Msger.broadcast, "额度修改失败");
                        }
                    }
                    else {
                        sendMessage(Msger.broadcast, "账号未找到");
                    }
                }
                else {
                    sendMessage(Msger.broadcast, "参数错误");
                }
                break;
            }
            //管理员申请修改联系方式
            case Msger.requestChangeContact: {
                String data = Msger.getValueByType(msg, Msger.requestChangeContact);
                if (data != null) {
                    String[] strs = data.split("&");
                    String idCode = strs[0];
                    String contact = strs[1];
                    Account account = AccountData.getAccountByIdCode(idCode);
                    if (account != null) {
                        AccountData.updatePlayerContact(account.getIdCode(), account.getNickName(), contact);
                        String detail = AccountData.getAccountDetail(account);
                        sendMessage(Msger.refreshAccountDetail, detail);
                        sendMessage(Msger.broadcast, "联系方式修改成功");
                    }
                    else {
                        sendMessage(Msger.broadcast, "账号未找到");
                    }
                }
                else {
                    sendMessage(Msger.broadcast, "参数错误");
                }
                break;
            }
            //管理员申请修改荣誉标签
            case Msger.requestChangeBadge: {
                String data = Msger.getValueByType(msg, Msger.requestChangeBadge);
                if (data != null) {
                    String[] strs = data.split("&");
                    String idCode = strs[0];
                    String badge = strs[1];
                    Account account = AccountData.getAccountByIdCode(idCode);
                    if (account != null) {
                        AccountData.updatePlayerBadge(account.getIdCode(), account.getNickName(), badge);
                        String detail = AccountData.getAccountDetail(account);
                        sendMessage(Msger.refreshAccountDetail, detail);
                        sendMessage(Msger.broadcast, "荣誉标签修改成功");
                        Player player = DataManager.getOnlinePlayerById(account.getIdCode()); //查询该账户角色是否在线
                        if (player != null) {
                            player.sendMessage(Msger.refreshPlayerInfo, player.getPlayerInfo()); //更新角色信息
                            DataManager.noticeAllBroadcast(account.getNickName() + "获得荣誉标签" + "【" + badge + "】");//发送全局消息给所有在线用户
                        }
                    }
                    else {
                        sendMessage(Msger.broadcast, "账号未找到");
                    }
                }
                else {
                    sendMessage(Msger.broadcast, "参数错误");
                }
                break;
            }
            //管理员申请修改用户聊天权限
            case Msger.requestAdjustChatLevel: {
                String data = Msger.getValueByType(msg, Msger.requestAdjustChatLevel);
                if (data != null) {
                    String[] strs = data.split("&");
                    String idCode = strs[0];
                    String level = strs[1];
                    Account account = AccountData.getAccountByIdCode(idCode);
                    if (account != null) {
                        ChatData.changeChatLevel(account, Integer.parseInt(level));
                        sendMessage(Msger.broadcast, "聊天权限等级调整成功"); //告诉管理员
                        Player player = DataManager.getOnlinePlayerById(account.getIdCode()); //查询该账户角色是否在线
                        if (player != null) {
                            player.sendMessage(Msger.refreshPlayerInfo, player.getPlayerInfo()); //更新角色信息
                            player.sendMessage(Msger.broadcast, "管理员调整了您的聊天权限为 " + ChatLevel.getDescByLevel(Integer.parseInt(level))); //告诉这个用户
                        }
                    }
                    else {
                        sendMessage(Msger.broadcast, "账号未找到");
                    }
                }
                else {
                    sendMessage(Msger.broadcast, "参数错误");
                }
                break;
            }
            //管理员添加账号
            case Msger.requestAddAccount: {
                String value = Msger.getValueByType(msg, Msger.requestAddAccount);
                if (value != null) {
                    String idCode = value.split("@")[0];
                    String nickName = value.split("@")[1];
                    String createTime = DateTimeUtil.localDateTimeToStr(LocalDateTime.now(), DateTimeUtil.DATE_FORMAT);
                    System.out.println("管理员请求添加新账号：" + msg);
                    if (!AccountData.isIdCodeAccess(idCode)) {
                        if (!AccountData.isNicknameAccess(nickName)) {
                            if (AccountData.managerCreateAccount(idCode, nickName, createTime)) { //持久化新账号并判断是否成功
                                sendMessage(Msger.managerAddAccountSuccess, "Ok");
                            }
                            else {
                                sendMessage(Msger.managerAddAccountFailed, "请稍后再试");
                            }
                            sendMessage(Msger.refreshAccountList, AccountData.getAccountListInfo(account -> true)); //更新账号列表信息
                        }
                        else {
                            sendMessage(Msger.managerAddAccountFailed, "昵称重复了");
                        }
                    }
                    else {
                        sendMessage(Msger.managerAddAccountFailed, "账号已存在");
                    }
                }
                else {
                    sendMessage(Msger.managerAddAccountFailed, "格式不正确");
                }
                break;
            }
            //管理员请求房间列表
            case Msger.requestRoomList: {
                sendMessage(Msger.managerRefreshRoomList, DataManager.getRoomListInfo()); //更新房间信息
                break;
            }
            //请求所有可玩棋类的列表
            case Msger.requestChessList: {
                List<Room> chessList = RoomData.getChessListInfo();
                if (!chessList.isEmpty()) {
                    //chessList根据名称进行排序，效果并不好，不要这样，代码暂时隐藏
                    //chessList.sort(Comparator.comparing(Room::getChessName));
                    StringBuilder sb = new StringBuilder();
                    for (Room room : chessList) {
                        sb.append(room.getClass().getSimpleName()).append("&")
                                .append(room.getChessName()).append("&")
                                .append(room.getAllModes()).append("&") //至少会有个”默认“
                                .append(RoomData.getChessRoomNum(room.getChessName()))
                                .append(";");
                    }
                    String s = sb.toString();
                    sendMessage(Msger.refreshChessList, s.substring(0, s.length() - 1));
                }
                else {
                    sendMessage(Msger.refreshChessList, "-1");
                }
                break;
            }
            //请求创建房间
            case Msger.requestCreateRoom: {
                System.out.println("管理员请求创建新房间：" + msg);
                String createRoomValue = Msger.getMsgValue(msg);
                String[] dates = createRoomValue.split("@", 6);
                if (dates.length == 6) {
                    try {
                        String className = dates[0];
                        String chessName = dates[1];
                        String roomName = dates[2];
                        boolean isSaveReport = Boolean.parseBoolean(dates[3]);
                        String modeName = dates[4];
                        String introduce = dates[5]; //为了兼容富文本标签对，需要确保introduce在最后一项
                        Room repeatRoom = DataManager.getRoomByName(roomName);
                        if (repeatRoom == null) {
                            RoomData.createRoom(className, chessName, roomName, isSaveReport, modeName, introduce); //创建房间
                            sendMessage(Msger.managerRefreshRoomList, DataManager.getRoomListInfo()); //更新房间信息
                            DataManager.noticeAllRefreshRoomList();//同时通知在线玩家更新房间列表
                        }
                        else {
                            sendMessage(Msger.broadcast, "创建房间失败:房间名重复了");
                        }
                    }
                    catch (Exception e) {
                        sendMessage(Msger.broadcast, "创建房间发生异常:" + e);
                        System.out.println("创建房间发生异常:" + e);
                    }
                }
                else {
                    sendMessage(Msger.broadcast, "创建房间失败: 格式不正确");
                    System.out.println("创建房间失败: 格式不正确");
                }
                break;
            }
            //请求克隆房间
            case Msger.requestCloneRoom: {
                String cloneRoomValue = Msger.getMsgValue(msg);
                String oldRoomName = cloneRoomValue.split("@")[0];
                String newRoomName = cloneRoomValue.split("@")[1];
                System.out.println("管理员请求克隆新房间：" + msg);
                Room exitRoom = DataManager.getRoomByName(oldRoomName);
                if (exitRoom != null) {
                    try {
                        Room repeatRoom = DataManager.getRoomByName(newRoomName);
                        if (repeatRoom == null) {
                            RoomData.cloneRoom(exitRoom, newRoomName); //克隆房间
                            sendMessage(Msger.managerRefreshRoomList, DataManager.getRoomListInfo()); //更新房间信息
                            DataManager.noticeAllRefreshRoomList();//同时通知在线玩家更新房间列表
                        }
                        else {
                            sendMessage(Msger.broadcast, "房间名重复了");
                        }
                    }
                    catch (Exception e) {
                        sendMessage(Msger.broadcast, "添加房间发生异常:" + e);
                        System.out.println("添加房间发生异常:" + e);
                    }
                }
                break;
            }
            //请求清理房间
            case Msger.requestCleanRoom: {
                String roomName = Msger.getMsgValue(msg);
                Room exitRoom = DataManager.getRoomByName(roomName);
                System.out.println("管理员清理房间：" + msg);
                if (exitRoom != null) {
                    exitRoom.removeAllPlayer();
                    DataManager.noticeAllBroadcast("管理员已清理" + roomName + "房间");
                    sendMessage(Msger.broadcast, "房间清理完毕");
                }
                break;
            }
            //请求关闭房间
            case Msger.requestCloseRoom: {
                String roomName = Msger.getMsgValue(msg);
                Room exitRoom = DataManager.getRoomByName(roomName);
                System.out.println("管理员关闭房间：" + msg);
                if (exitRoom != null) {
                   /* long count = DataManager.roomList.stream().filter(room -> room.getClass() == exitRoom.getClass()).count();
                    if (count > 1) {

                    }
                    else {
                        sendMessage(Msger.broadcast, "该棋种只剩一个房间不能关闭");
                    }*/
                    if (exitRoom.getPlayerNum() == 0) {
                        if (DataManager.roomList.size() > 1) {
                            RoomData.removeRoom(exitRoom); //移除房间
                            sendMessage(Msger.managerRefreshRoomList, DataManager.getRoomListInfo()); //更新房间信息
                        }
                        else {
                            sendMessage(Msger.broadcast, "只剩最后一个房间了不能关闭");
                        }
                    }
                    else {
                        sendMessage(Msger.broadcast, "该房间有玩家在不能关闭");
                    }
                }
                break;
            }
            //请求查看该房间今日战报
            case Msger.requestTodayRecords: {
                String value = Msger.getValueByType(msg, Msger.requestTodayRecords);
                if (value != null) {
                    String roomName = value.split("@")[0];
                    String todayDate = value.split("@")[1];
                    sendMessage(Msger.refreshTodayRecords, DataManager.getRoomTodayRecords(roomName, todayDate));
                }
                break;
            }
            //请求查看该房间多日战报
            case Msger.requestDaysRecords: {
                String value = Msger.getValueByType(msg, Msger.requestDaysRecords);
                if (value != null) {
                    String roomName = value.split("@")[0];
                    String startDate = value.split("@")[1];
                    String endDate = value.split("@")[2];
                    LocalDateTime startDt = DateTimeUtil.strToLocalDateTime(startDate + " 00:00:00", DateTimeUtil.ALL_FORMAT);
                    LocalDateTime endDt = DateTimeUtil.strToLocalDateTime(endDate + " 00:00:00", DateTimeUtil.ALL_FORMAT);
                    long between = DateTimeUtil.betweenDay(startDt, endDt);
                    String[] days = new String[(int) between + 1];
                    for (int i = 0; i < between + 1; i++) {
                        days[i] = DateTimeUtil.localDateTimeToStr(startDt.plusDays(i), DateTimeUtil.DATEFORMAT);
                    }
                    sendMessage(Msger.refreshTodayRecords, DataManager.getRoomDaysRecords(roomName, days));
                }
                break;
            }
            //请求查看房间配置信息
            case Msger.requestRoomConfigInfo: {
                String value = Msger.getValueByType(msg, Msger.requestRoomConfigInfo);
                sendMessage(Msger.refreshRoomConfigInfo, RoomData.getRoomConfigInfo(value));
                break;
            }
            //请求查看该日登录用户
            case Msger.requestTodayLogin: {
                String value = Msger.getValueByType(msg, Msger.requestTodayLogin);
                String names = AccountData.getThisDayLoginPlayers(value);
                int count = names.split("，").length;
                if (names.equals("-1")) {
                    names = "";
                    count = 0;
                }
                sendMessage(Msger.refreshTodayLogin, "共" + count + "人：\n" + names);
                break;
            }
            //请求查看系统资源信息
            case Msger.requestSystemInfo: {
                sendMessage(Msger.refreshSystemInfo, DataManager.getSystemInfo());
                break;
            }
            //请求发送群发通知
            case Msger.requestGroupNotice: {
                String value = Msger.getValueByType(msg, Msger.requestGroupNotice);
                DataManager.sendAllInfoDialog(value);
                break;
            }
            //请求创建一封公告
            case Msger.requestAddNotification: {
                String value = Msger.getValueByType(msg, Msger.requestAddNotification);
                String id = DateTimeUtil.localDateTimeToStr(LocalDateTime.now(), DateTimeUtil.ALLFORMAT); //根据当前时间生成公告的唯一id
                NotificationData.createNotification(id, value); //保存公告文件到本地
                DataManager.noticeAllNotification();//在线用户直接收到公告通知，不在线用户下次登录时受到通知
                sendMessage(Msger.refreshActiveNotifications, NotificationData.getActiveNotifications());
                break;
            }
            //请求关闭一封公告
            case Msger.requestCloseNotification: {
                String id = Msger.getValueByType(msg, Msger.requestCloseNotification);
                NotificationData.closeNotificationById(id); //将该公告移动到旧公告文件夹里
                sendMessage(Msger.refreshActiveNotifications, NotificationData.getActiveNotifications());
                break;
            }
            //管理员获取所有活跃的公告列表，包含id和内容
            case Msger.requestActiveNotifications: {
                sendMessage(Msger.refreshActiveNotifications, NotificationData.getActiveNotifications());
                break;
            }
            //获取过时的公告id列表
            case Msger.requestOldNotificationIds: {
                sendMessage(Msger.refreshOldNotificationIds, NotificationData.getOldNotificationIds());
                break;
            }
            //根据id获取过时的公告内容
            case Msger.requestOldNotificationDetail: {
                String id = Msger.getValueByType(msg, Msger.requestOldNotificationDetail);
                sendMessage(Msger.refreshOldNotificationDetails, NotificationData.getOldNotificationById(id));
                break;
            }
        }
    }

    //回收该角色的io流与socket，适当延迟10ms防止回收太快产生的异常
    public void recycle() {
        try {
            this.keepFlag = false;
            Thread.sleep(10);
            this.dis.close();
            this.dos.close();
            this.socket.close();
        }
        catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 当管理员登录成时执行
     */
    public void onLoginSuccess() {
        this.keepFlag = true;
        this.heartTime = System.currentTimeMillis();
        new Thread(this).start();
        sendMessage(Msger.managerLoginSuccess, "Ok");
    }

    /**
     * 向客户端发送消息
     */
    public void sendMessage(String type, String value) {
        String msg = Msger.createMsg(type, value);
        try {
            dos.writeUTF(msg);
        }
        catch (IOException e) {
            e.printStackTrace();
            recycle();
        }
    }

    public boolean isTimeOut() {
        return System.currentTimeMillis() - heartTime > 1000 * 60 * 5;
    }


    public static void main(String[] args) {
        String data = "1;2;3;4;5";
        String cachedNoticeIdsStr = "1;2;3;4";
        List<String> ntfIdsList = Arrays.asList(data.split(";")); //后台发的通知列表
        List<String> cachedIdsList = Arrays.asList(cachedNoticeIdsStr.split(";")); //本地存的通知列表
        boolean isDisjoint = Collections.disjoint(ntfIdsList, cachedIdsList); //是不存在相交的，完全新的
        System.out.println(isDisjoint);
        List<String> unReadList = new ArrayList<>(ntfIdsList);
        unReadList.removeAll(cachedIdsList); //移除后台发的中所有本地已经缓存过的
        String cachedIdsStr = String.join(";", unReadList);//再把移除过的拼接回去
        System.out.println(cachedIdsStr);
    }
}
